/*****************************************************************************************************
*       SRLOS Team
*@filename:     kernel_task.c
*@brief   :     this file defines some common task using functions
*@author  :     bloceanc
*@note    :     we need some asm function codes
*@comment :
*@datetime:     24/04/2010 21:26:33
*
*		创建线程或者默认线程时，参数（R0/R0~R1）的压栈顺序可能有错！！！
*****************************************************************************************************/
#ifndef _K_TASK_C_
#define _K_TASK_C_

/**
 * 		INCLUDE FILES
 */

#include "../mem/k_mem_physical.h"
#include "../mem/k_mem_sysmmu.h"
#include "task_basedefine.h"
#include "kernel_task_def.h"
#include "../k_common_asm.h"

/**
 * 		MACROS
 * 	The following maros have been tested already, don't change any thing, specially changing charactor '&'!
 */

// save thread context, we'd not better save SPSR, because there is no SPSR in _sys mode
#define	K_TASK_CPU_CONTEXT_SAVE(__thread__)		\
	__asm__ __volatile__(   					\
		"STMFD R13!,{R0-R12,R14}\n\t"			\
		"MRS R0, CPSR\n\t"						\
		"STMFD R13!, {R0}\n\t"					\
		"STR R13, %0\n\t"						\
		:"=m"(__thread__->cpu_reg_sp)			\
		)



// resume thread context
#define K_TASK_CPU_CONTEXT_RESUME(__thread__)	\
	__asm__ __volatile__(			    		\
		"LDR R13, %0\n\t"						\
		"LDMFD R13!, {R0}\n\t"					\
		"MSR CPSR, R0\n\t"						\
		"LDMFD R13!,{R0-R12,R14}\n\t"			\
		::"m"(__thread__->cpu_reg_sp)			\
	)

// start a new thread. it will jump to the context resume to running...
// note	  : cause this is a new thread, so, there is no cpu schedule context. Just return get out interrupt!
#define	K_TASK_NEW_CONTEXT_RESUME(__thread__, __pc_addr__)	\
	__asm__ __volatile__(	\
		"LDR R13, %0\n\t"	\
		"LDR R15, %1\n\t"	\
		::"m"(__thread__->cpu_reg_sp),"m"(__pc_addr__)			\
	)

// macro for scanning process list and remove PCB of which to be found from list
#define K_TASK_SCAN_PROCESS_REMOVEPCB(__proc_list__,__del_proc__)	\
{	\
	K_PProcessList __proc_cur__ = __proc_list__.next;	\
	K_PProcessList __proc_pre__ = &__proc_list__;	\
	while(__proc_cur__)	\
	{	\
		if(__proc_cur__ == __del_proc__)	\
		{	\
			__proc_pre__->next = __proc_cur__->next;	\
			break;	\
		}	\
		__proc_pre__ = __proc_cur__;	\
		__proc_cur__ = __proc_cur__->next;	\
	}	\
}

// macro for scanning thread list and remove TCB of which to be found from list
#define K_TASK_SCAN_THREAD_REMOVETCB(__thread_list__,__thread__)	\
{	\
	K_PThreadList __thread_pre__ = &__thread_list__;	\
	K_PThreadList __thread_cur__ = __thread_list__.next;	\
	while(__thread_cur__)	\
	{	\
		if(__thread_cur__ == __thread__)	\
		{	\
			__thread_pre__->next = __thread_cur__->next;	\
			break;	\
		}	\
		__thread_pre__ = __thread_cur__;	\
		__thread_cur__ = __thread_cur__->next;	\
	}	\
}

/**
*               GLOBALS
*/
K_PProcess				g_p_cur_process;
K_PThread	    		g_p_cur_thread;

/**
 * 				LOCALS
 */
/* global process list */
static K_ProcessList	g_active_process_list;
static K_ProcessList	g_suspend_process_list;
static K_ProcessList	g_waiting_process_list;

/* task terminate list */
static K_ThreadList		g_terminate_threadlist;
static K_ProcessList	g_terminate_processlist;

/* task schedule state */
static unsigned int		g_task_schedule_state;	// 1 -- Disable task schedule; 0 -- Enable task schedule!

/**
 *      EXTERN FUNCTIONS
 *
 */
/* new thread start address */
extern unsigned int e_thread_start_addr;

/** heap functions **/
extern void *k_mm_os_heap_allocate(unsigned int size);
extern void k_mm_os_heap_free(void *mem_addr);
extern void *k_mm_usr_heap_allocate(unsigned int size);
extern void k_mm_usr_heap_free(void *mem_addr);

/** the following functions return physical address **/
extern void * k_mem_mmu_allocate_flpt_return_physical_address(void);
extern void k_mem_mmu_free_flpt_with_physical_address(unsigned int phy_addr);

/** the following functions return virtual address **/
extern void *k_mem_mmu_allocate(EN_K_MEM_PHY_USE_MODE vm_mode, unsigned int page_count);
extern void k_mem_mmu_free(void *vir_addr);

/** other **/
extern unsigned int *k_task_load(char *dir, int load_flag, unsigned int *size);
extern void k_task_codesegment_swap(unsigned int *p_newflpt, unsigned int addr_codesegment, unsigned int *code_addr, unsigned int seg_size);

/** mmu switch */
extern unsigned int k_mmu_switch(unsigned int new_addr);

/**
 *
 *      LOCAL    FUNCTIONS
 */
int k_task_create_process(K_EN_TASK_PRIORITY priority, K_EN_PROCESSTYPE type, unsigned int addr_codestart, char *dir, int load_flag, int narg, char *argv[]);
static K_PThreadList k_task_create_proc_default_thread(K_EN_TASK_PRIORITY priority,	unsigned int *usr_stack_addr, int instr_type, unsigned int  addr_codestart, int argn, char *argv[]);
void k_task_exit_thread(unsigned int thread_handle);
void k_task_schedule(K_EN_THREAD_STATE save_thread_state, K_EN_PROCESS_STATE save_process_state, int isforced);
static void k_task_free_pcb(K_PProcess p_proc);
static void k_task_free_tcb(K_PThreadList p_thread, unsigned int stack_usr_del);
void k_task_terminate_process(K_PProcessList proclist);
unsigned int k_task_create_thread(K_EN_TASK_PRIORITY priority, int stacksize, int instr_type, unsigned int addr_codestart, unsigned int state, void *pVoid);
void k_task_terminate_thread(K_PThreadList threadlist);
static K_PProcess k_task_get_next_process(void);
static K_PThreadList k_task_get_next_threadelement(void);
unsigned int k_task_is_schedule_enable(void);
void k_task_disable_schedule(void);
void k_task_enable_schedule(void);
void k_task_add_thread2list(K_PThreadList thread, K_PProcess process, K_EN_THREAD_STATE state);
void k_task_add_process2list(K_PProcessList process, K_EN_PROCESS_STATE state);
static void k_task_thread_terminate_thread(void);
static void k_task_process_terminate_process(void);
static K_EN_TASK_PRIORITY k_task_next_priority(K_EN_TASK_PRIORITY cur_pri, K_EN_TASK_PRIORITY max_pri);
void k_task_suspend_thread(K_PThreadList threadlist);
void k_task_resume_thread(K_PThreadList threadlist);
void k_task_suspend_process(K_PProcessList proclist);
void k_task_resume_process(K_PProcessList proclist);

/**
 * @BRIEF	: Create new process
 * @PARAM	: priority          process priority
 * @PARAM	: type              process type
 * @PARAM	: addr_codestart    process start virtual address
 * @PARAM   : dir               load_flag = 0,applicaton file path; else is the address in ROM.
 * @PARAM   : load_flag         0 load from file, else load from ROM and this parameter indicates the code size in ROM will be loaded
 * @RETRUN	: 1 success, otherwise failed
 * @WARNING	:
 * @NOTE    : this function will create a new process
 *          : and add it to process list.this function thinks
 *          : the codeseg of applications has been loaded into
 *          : memory!
 */
int k_task_create_process(K_EN_TASK_PRIORITY priority, K_EN_PROCESSTYPE type, unsigned int addr_codestart, char *dir, int load_flag, int narg, char *argv[])
{
    // process describe block
    K_PProcess      p_newprocess;
    unsigned int    *p_thread_usr_stack;
    unsigned int    usr_stack_size;
    unsigned int    size_code;
    unsigned int    *p_code_addr;
    K_PProcessList  p_list_element;
    K_PThreadList   p_thread_list;
	unsigned int	*p_slpt;

    // first, we need a new flpt for new process.
    unsigned int phy_flpt_addr = (unsigned int)k_mem_mmu_allocate_flpt_return_physical_address();

    if(phy_flpt_addr == 0)
    {
        // we failed to create new flpt for process
        return 0;
    }

    // allocate a new SLPT for new process to used for stack of default thread
    p_slpt = k_mem_mmu_allocate(K_MEM_PHY_SYSTEM, 1);
    if(p_slpt == 0)
    {
        k_mem_mmu_free_flpt_with_physical_address(phy_flpt_addr);
        return 0;
    }

    p_list_element = k_mm_os_heap_allocate(sizeof(K_ProcessList));

    if(p_list_element == 0)
    {
        k_mem_mmu_free_flpt_with_physical_address(phy_flpt_addr);
        k_mem_mmu_free(p_slpt);
        return 0;
    }

    // new process block
    p_newprocess = k_mm_os_heap_allocate(sizeof(K_Process));
    if(p_newprocess == 0)
    {
        // we failed to allocate new process describe block
        // we should free we have allocated FLPT
        k_mem_mmu_free_flpt_with_physical_address(phy_flpt_addr);
        k_mm_os_heap_free(p_list_element);
        k_mem_mmu_free(p_slpt);
        // and return failed
        return 0;
    }

    // size of usr mode stack
    usr_stack_size  = K_MAINTHREAD_STACK_SIZE;
    K_BOUND_4KB(usr_stack_size);

    // allocate default usr stack for defualt thread in father space, but we will change it to child space later
    p_thread_usr_stack = k_mem_mmu_allocate(K_MEM_PHY_NORMAL , usr_stack_size >> 12);
    if(p_thread_usr_stack == 0)
    {
        k_mem_mmu_free_flpt_with_physical_address(phy_flpt_addr);
        k_mem_mmu_free(p_slpt);
        // free process block
        k_mm_os_heap_free(p_newprocess);

        k_mm_os_heap_free(p_list_element);

        return 0;
    }

    // create default thread of process. we need support multi-thread ^_^
    p_thread_list = k_task_create_proc_default_thread(priority,		// must be K_MAINTHREAD_STACK_ADDR. This is the real address in new process
								(unsigned int *)K_MAINTHREAD_STACK_ADDR, 0, K_TASK_APP_CODESEG_START, narg, argv);

    if(p_thread_list == 0)
    {
        // we failed to allocate new thread describe block
        // we should free we have allocated FLPT
        k_mem_mmu_free_flpt_with_physical_address(phy_flpt_addr);

        k_mem_mmu_free(p_slpt);
        // free process block
        k_mm_os_heap_free(p_newprocess);

        k_mem_mmu_free(p_thread_usr_stack);

        k_mm_os_heap_free(p_list_element);

        // return failed
        return 0;
    }
    {
        // reset FLPT of new process,-->thread's user mode stack
        // here we have to allocate a new memory page for SLPT
        // insert new SLPT
        unsigned int phy_addr_stack;
        unsigned int k;
        for(k = 0; k < 4; k++)
        {
            K_MEM_MMU_FILL_FMPT(K_MEM_MMU_SYS_VIR2PHY((unsigned int)p_slpt + (k << 10)), (K_MAINTHREAD_STACK_ADDR + (k << 20)), K_MEM_MMU_DOMAIN_SYSTEM, K_MEM_MMU_SYS_PHY2VIR(phy_flpt_addr));
        }

        K_MEM_MMU_GET_PHYADDR((unsigned int)p_thread_usr_stack, phy_addr_stack, K_MEM_MMU_SYS_PHY2VIR(phy_flpt_addr))
		for(k = 0; k < (usr_stack_size >> 12); k++)
        {
			// insert user mode stack page
			K_MEM_MMU_FILL_SMPT((phy_addr_stack + (k << 12)), (K_MAINTHREAD_STACK_ADDR + (k << 12)),( (unsigned int)(K_MEM_MMU_SYS_PHY2VIR(phy_flpt_addr))), K_MEM_MMU_AP_USER_READWRITE, K_MEM_MMU_WRITE_MODE_WB, K_MEM_MMU_WRITE_MODE_B)

			// clear current process thread user stack page...we have transate to new process
			K_MEM_MMU_FREE_VIR((unsigned int)p_thread_usr_stack + (k << 12), ((unsigned int *)(K_MEM_MMU_SYS_PHY2VIR(g_p_cur_process->fsttb_phy_addr))));
		}
        // we can't free p_slpt, because it is in OS space!
    }

    // now fill the new process block
    p_newprocess->suspend_threads.thread = 0;
    p_newprocess->suspend_threads.next = 0;
    p_newprocess->active_threads.thread = 0;
    p_newprocess->active_threads.next = p_thread_list;
    p_newprocess->thread_running = 0;
    p_newprocess->fsttb_phy_addr = phy_flpt_addr;
    p_newprocess->proc_heappool.hpool_size = 0;
    p_newprocess->proc_heappool.hp_heapcount = 0;
    p_newprocess->proc_heappool.hp_firstheap = 0;
    p_newprocess->priority = priority;
    p_newprocess->cur_pri = priority;
    p_newprocess->proctype = type;
    p_newprocess->state = K_TASK_THREAD_STATE_ACTIVE;
	p_newprocess->sched_count = 0;
	p_newprocess->sched_endcnt = 0;

	// set PCB pointer
	p_newprocess->parent_proclist = p_list_element;

    // now load the new process codesegmen
    p_code_addr = k_task_load(dir, load_flag, (unsigned int *)&size_code);
    if(p_code_addr == 0)
    {
        // sorry, failed!
        k_mem_mmu_free_flpt_with_physical_address(phy_flpt_addr);

        k_mem_mmu_free(p_slpt);
        // free process block
        k_mm_os_heap_free(p_newprocess);

        k_mem_mmu_free(p_thread_usr_stack);

        k_mm_os_heap_free(p_list_element);

        // terminate default thread

        k_mm_os_heap_free(p_thread_list->thread);
        k_mm_os_heap_free(p_thread_list);

        // free user space of child process
        k_mem_mmu_freeprocessusrspace(((unsigned int *)K_MEM_MMU_SYS_PHY2VIR(phy_flpt_addr)));
        return 0;
    }

    // swap the code segment to child process
    k_task_codesegment_swap(((unsigned int *)K_MEM_MMU_SYS_PHY2VIR(phy_flpt_addr)), K_TASK_APP_CODESEG_START, p_code_addr, size_code);

    // add new process to process list
	k_task_add_process2list(p_list_element, K_TASK_PROCESS_STATE_ACTIVE);
/*    p_list_element->next = g_active_process_list.next;
    g_active_process_list.next = p_list_element;
*/
    return 1;
}

/**
 * @BRIEF	:   Create new thread
 * @PARAM	:   priority          thread priority
 * @PARAM	:   stacksize         user mode stack size
 * @PARAM   :   instr_type        indicate codes instruction using. ARM 0, THUMB 1
 * @PARAM	:   addr_codestart    process start virtual address
 * @PARAM	:   state             create state. 0 suspend. 1 run immediately
 * @PARAM	:	pVoid			  Thread Proc Parameter pointer
 * @RETRUN	:   0 failed.Otherwise success!
 * @WARNING	: =>when thread run first time, it's in system mode.
 *          : because we treat it as it has just been suspend.
 *          : the first running is just like resume.So, we should
 *          : make the mode stack of thread looking like was
 *          : suspend.
 *          : We should put some informations into the mode stack
 *          : return address(here is starting address),registers
 *          : and so on.....Otherwise, thread can't run corrected
 */
unsigned int k_task_create_thread(K_EN_TASK_PRIORITY priority, int stacksize, int instr_type, unsigned int addr_codestart, unsigned int state, void *pVoid)
{
    // first we should allocate thread block
    K_PThread p_newthread = k_mm_os_heap_allocate(sizeof(K_Thread));
    K_PThreadList   p_threadlist;

    char *p_sysmod_stack;
    char *p_usrmod_stack;
    unsigned int *p_cur_sysmod_sp;

    if(p_newthread == 0)
    {
        // we failed .
        return 0;
    }

    p_threadlist = k_mm_os_heap_allocate(sizeof(K_ThreadList));
    if(p_threadlist == 0)
    {
        // failed
        k_mm_os_heap_free(p_newthread);
        return 0;
    }

    // allocate mode stack and user mode statck
    // we allocate system mode stack from OS space ..User could not access this stack!
    p_sysmod_stack  = k_mm_os_heap_allocate(K_TASK_THREAD_SYSMOD_STACK_SIZE);
    if(p_sysmod_stack == 0)
    {
        k_mm_os_heap_free(p_newthread);
        k_mm_os_heap_free(p_threadlist);
        return 0;
    }

    // we should allocate user mode stack from user heap not OS heap!
    p_usrmod_stack  = k_mm_usr_heap_allocate(stacksize);
    if(p_usrmod_stack == 0)
    {
        k_mm_os_heap_free(p_newthread);
        k_mm_os_heap_free(p_threadlist);
        // we should free the system mode stack
        k_mm_os_heap_free(p_sysmod_stack);
        return 0;
    }

    // now, we should fill system mode stack information
    // more information see <SRLOS interrupt design> doc
#ifdef _K_SYS_LITTLEENDIAN_
    p_cur_sysmod_sp = (unsigned int *)((char *)p_sysmod_stack + K_TASK_THREAD_SYSMOD_STACK_SIZE);
    p_newthread->p_thread_sys_stack = (unsigned int *)p_sysmod_stack;
    p_newthread->p_thread_usr_stack = (unsigned int *)(p_usrmod_stack);

    // push R14, here is addr_codestart
    *(--p_cur_sysmod_sp) = addr_codestart;

    // push SPSR.we should create a new SPSR.2 flags we need to indicate: CPU mode, and Instruction
    if(instr_type)
    {
        *(--p_cur_sysmod_sp) = 0x10;
    }
    else
    {
        *(--p_cur_sysmod_sp) = 0x30;
    }

    // push R1~R12.In fact here, we don't push anything.but leave the space
    p_cur_sysmod_sp -= 12;  // R1~R12;

	// push R0 as the parameter of thread function
	*(--p_cur_sysmod_sp) = (unsigned int)pVoid;

    // push R13_usr(SP_usr)(stack top! Pre-decriment Store!so, we can't sub 1)
    *(--p_cur_sysmod_sp) = (unsigned int)p_newthread->p_thread_usr_stack + stacksize;

    // push R14_usr
    *(--p_cur_sysmod_sp) = 0;        // here, I have some questions:
                                    // how OS knows thread has returned by thread itself!
                                    // use this?????

    // now, we have to indicate the sp_sys(in fact, this register is not exist, we just call it)
    // when resume using this to find the system mode stack pointer and resume context of CPU
    p_newthread->cpu_reg_sp = (unsigned int)(p_cur_sysmod_sp);    // we use STMFD/LDMFD instruction, so we should make sure sp point to a
                                                    // last used space!So we, can't sub p_cur_sysmod_sp!
	p_newthread->p_thread_sys_init_top	= (unsigned int *)((char *)p_sysmod_stack + K_TASK_THREAD_SYSMOD_STACK_SIZE);
#else
    p_cur_sysmod_sp = (unsigned int *)p_sysmod_stack;
    p_newthread->p_thread_sys_stack = p_cur_sysmod_sp;
    p_newthread->p_thread_usr_stack = p_usrmod_stack;

    // push R14, here is addr_codestart
    *(++p_cur_sysmod_sp) = addr_codestart;

    // push SPSR.we should create a new SPSR.2 flags we need to indicate: CPU mode, and Instructon
    if(instr_type)
    {
        *(++p_cur_sysmod_sp) = 0x10;
    }
    else
    {
        *(++p_cur_sysmod_sp) = 0x30;
    }

	// push R1~R12.In fact here, we don't push anything.but leave the space
    p_cur_sysmod_sp += 12;  // R1~R12;

	// push R0 as parameter of thread function
	*(++p_cur_sysmod_sp) = (unsigned int)pVoid;


    // push R13_usr(SP_usr)
    *(++p_cur_sysmod_sp) = (unsigned int)p_newthread->p_thread_usr_stack;

    // push R14_usr
    *(++p_cur_sysmod_sp) = 0;        // here, I have some questions:
                                    // how OS knows thread has returned by thread itself!
                                    // use this?????

    // now, we have to indicate the sp_sys(in fact, this register is not exist, we just call it)
    // when resume using this to find the system mode stack pointer and resume context of CPU
    p_newthread->cpu_reg_sp = p_cur_sysmod_sp;
	p_newthread->p_thread_sys_init_top = p_sysmod_stack;

#endif
    p_newthread->times = 0;
    p_newthread->priority = priority;
    p_newthread->cur_pri = priority;
    p_newthread->state  = state | K_TASK_THREAD_STATE_NEW;
	p_newthread->parent_process = g_p_cur_process;
	p_newthread->thread_type = K_TASK_THREAD_TYPE_OTHER;	// this is not main thread.main thread must be defualt thread
	p_newthread->parent_tcblist = p_threadlist;
	p_newthread->sched_count = 0;
	p_newthread->sched_endcnt = 0;

    // create thread list element
    p_threadlist->thread = p_newthread;
    p_threadlist->next = 0;

    // now we insert the new thread to process thread list.
	k_task_add_thread2list(p_threadlist, g_p_cur_process->parent_proclist, state);
/*    if(state == K_TASK_THREAD_STATE_ACTIVE)
    {
        p_threadlist->next = g_p_cur_process->active_threads.next;
        g_p_cur_process->active_threads.next = p_threadlist;
    }
    else
    {
        p_threadlist->next = g_p_cur_process->suspend_threads.next;
        g_p_cur_process->suspend_threads.next = p_threadlist;
    }
*/
    return 1;
}

/**
 * @BRIEF	:   Create default thread
 * @PARAM	:   priority          thread priority
 * @PARAM   :   usr_stack_addr    usr mode stack address(this always fixed)
 * @PARAM   :   instr_type        indicate codes instruction using. ARM 0, THUMB 1
 * @PARAM	:   addr_codestart    process start virtual address(this always fixed)
 * @PARAM	:	argn			  parameter count in command line
 * @PARAM	:	argv			  parameter list in command line
 * @RETRUN	:   0 failed.Thread list element.
 * @WARNING	: =>when thread run first time, it's in system mode.
 *          : because we treat it as it has just been suspend.
 *          : the first running is just like resume.So, we should
 *          : make the mode stack of thread looking like was
 *          : suspend.
 *          : We should put some informations into the mode stack
 *          : return address(here is starting address),registers
 *          : and so on.....Otherwise, thread can't run corrected
 */
static K_PThreadList k_task_create_proc_default_thread(K_EN_TASK_PRIORITY priority,
	unsigned int *usr_stack_addr, int instr_type, unsigned int  addr_codestart, int argn, char *argv[])
{
    // first we should allocate thread block
    K_PThread p_newthread = k_mm_os_heap_allocate(sizeof(K_Thread));
    K_PThreadList   p_threadlist;

    char *p_sysmod_stack;
    char *p_usrmod_stack = (char *)usr_stack_addr;
    unsigned int *p_cur_sysmod_sp;

    if(p_newthread == 0)
    {
        // we failed .
        return 0;
    }

    p_threadlist = k_mm_os_heap_allocate(sizeof(K_ThreadList));
    if(p_threadlist == 0)
    {
        // failed
        k_mm_os_heap_free(p_newthread);
        return 0;
    }

    // allocate mode stack and user mode statck
    // we allocate system mode stack from OS space ..User could not access this stack!
    p_sysmod_stack  = k_mm_os_heap_allocate(K_TASK_THREAD_SYSMOD_STACK_SIZE);
    if(p_sysmod_stack == 0)
    {
        k_mm_os_heap_free(p_newthread);
        k_mm_os_heap_free(p_threadlist);
        return 0;
    }

    // we can't allocate usr mode stack
    p_usrmod_stack  = (char *)usr_stack_addr;
    if(p_usrmod_stack == 0)
    {
        k_mm_os_heap_free(p_newthread);
        k_mm_os_heap_free(p_threadlist);
        // we should free the system mode stack
        k_mm_os_heap_free(p_sysmod_stack);
        return 0;
    }

    // now, we should fill system mode stack information
    // more information see <SRLOS interrupt design> doc
#ifdef _K_SYS_LITTLEENDIAN_
    p_cur_sysmod_sp = (unsigned int *)((char *)p_sysmod_stack + K_TASK_THREAD_SYSMOD_STACK_SIZE);
    p_newthread->p_thread_sys_stack = (unsigned int *)(p_sysmod_stack);
    p_newthread->p_thread_usr_stack = (unsigned int *)(p_usrmod_stack);

    // push R14, here is addr_codestart
    *(--p_cur_sysmod_sp) = addr_codestart;

    // push SPSR.we should create a new SPSR.2 flags we need to indicate: CPU mode, and Instructon
    if(instr_type)
    {
        *(--p_cur_sysmod_sp) = 0x10;
    }
    else
    {
        *(--p_cur_sysmod_sp) = 0x30;
    }

    // push R2~R12.In fact here, we don't push anything.but leave the space
    p_cur_sysmod_sp -= 11;  // R12~R2;
	// use R0 ~ R1 for parameters of process main thread
	*(--p_cur_sysmod_sp) = (unsigned int)argv;	// R1
	*(--p_cur_sysmod_sp) = (unsigned int)argn;	// R0

    // push R13_usr(SP_usr)
    *(--p_cur_sysmod_sp) = (unsigned int)p_newthread->p_thread_usr_stack + K_MAINTHREAD_STACK_SIZE;

    // push R14_usr
    *(--p_cur_sysmod_sp) = 0;        // here, I have some questions:
                                    // how OS knows thread has returned by thread itself!
                                    // use this?????

    // now, we have to indicate the sp_sys(in fact, this register is not exist, we just call it)
    // when resume using this to find the system mode stack pointer and resume context of CPU
    p_newthread->cpu_reg_sp = (unsigned int)(p_cur_sysmod_sp);    // we use STMFD/LDMFD instruction, so we should make sure sp point to a
                                                    // last used space!So we can't sub p_cur_sysmod_sp!
	p_newthread->p_thread_sys_init_top	= (unsigned int *)((char *)p_sysmod_stack + K_TASK_THREAD_SYSMOD_STACK_SIZE);
#else
    p_cur_sysmod_sp = (unsigned int *)p_sysmod_stack;
    p_newthread->p_thread_sys_stack = p_cur_sysmod_sp;
    p_newthread->p_thread_usr_stack = p_usrmod_stack;

    // push R14, here is addr_codestart
    *(++p_cur_sysmod_sp) = addr_codestart;

    // push SPSR.we should create a new SPSR.2 flags we need to indicate: CPU mode, and Instructon
    if(instr_type)
    {
        *(++p_cur_sysmod_sp) = 0x10;
    }
    else
    {
        *(++p_cur_sysmod_sp) = 0x30;
    }

    // push R2~R12.In fact here, we don't push anything.but leave the space
    p_cur_sysmod_sp += 12;  // R2~R12;

	// use R0 ~ R1 for parameters of process main thread
	*(++p_cur_sysmod_sp) = (unsigned int)argv;	// R1
	*(++p_cur_sysmod_sp) = (unsigned int)argn;	// R0


    // push R13_usr(SP_usr)
    *(++p_cur_sysmod_sp) = (unsigned int)p_newthread->p_thread_usr_stack;

    // push R14_usr
    *(++p_cur_sysmod_sp) = 0;        // here, I have some questions:
                                    // how OS knows thread has returned by thread itself!
                                    // use this?????

    // now, we have to indicate the sp_sys(in fact, this register is not exist, we just call it)
    // when resume using this to find the system mode stack pointer and resume context of CPU
    p_newthread->cpu_reg_sp = (unsigned int)(p_cur_sysmod_sp);
	p_newthread->p_thread_sys_init_top	= p_sysmod_stack;
#endif
    p_newthread->times = 0;
    p_newthread->priority = priority;
    p_newthread->cur_pri = priority;
    p_newthread->state  = K_TASK_THREAD_STATE_ACTIVE | K_TASK_THREAD_STATE_NEW;
	p_newthread->parent_process = g_p_cur_process;
	p_newthread->thread_type = K_TASK_THREAD_TYPE_MAIN;		// default thread is main thread
	p_newthread->parent_tcblist = p_threadlist;
	p_newthread->sched_count = 0;
	p_newthread->sched_endcnt = 0;

    // create thread list element
    p_threadlist->thread = p_newthread;
    p_threadlist->next = 0;

    return p_threadlist;
}

/**
 * @BRIEF	: Exit thread
 * @PARAM	: p_thread        threadlist
 * @PARAM	: stack_usr_del	  whether delete usr mode stack: 1 delete, 0 leave
 * @RETRUN	: void
 * @WARNING	: This function doesn't diable task schedule
 * @NOTE    : this function will kill a thread, and free the thread block
 */
static void k_task_free_tcb(K_PThreadList p_thread, unsigned int stack_usr_del)
{
	// first free stack
	if(stack_usr_del)
	{
		k_mm_usr_heap_free(p_thread->thread->p_thread_usr_stack);
	}
	k_mm_os_heap_free(p_thread->thread->p_thread_sys_stack);

	// free some other resources before delete TCB! Functions can be added here  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

	// second free TCB
	k_mm_os_heap_free(p_thread->thread);
	k_mm_os_heap_free(p_thread);
}


/**
 * @BRIEF	: Exit process
 * @PARAM	: p_proc
 * @WARNING	:
 * @NOTE    : this function will kill a process and all thread belonged to it
 */
static void k_task_free_pcb(K_PProcess p_proc)
{
    K_PThreadList p_thread;
	K_PThreadList p_list;
	K_PProcessList p_prolist;

    if(p_proc->proctype == K_TASK_PROCESS_TYPE_SYS)
    {
        // we can't kill a sytem process
        return;
    }

    // first, terminate all threads belonging to process
	p_thread = p_proc->suspend_threads.next;
	while(p_thread != 0)
	{
		// free system mode stack
		k_mm_os_heap_free(p_thread->thread->p_thread_sys_stack);
		p_list = p_thread;
		p_thread = p_thread->next;

		// free current thread TCB and TCL
		k_task_free_tcb(p_list , 0);	// should not free usr mode stack! the memory has been disabled here.because process has been
										// suspended waiting to be terminated and MMU table is invalid,
										// will invoke k_mem_mmu_freeprocessusrspace!
	}

	p_thread = p_proc->active_threads.next;
	while(p_thread != 0)
	{
		// free system mode stack
		k_mm_os_heap_free(p_thread->thread->p_thread_sys_stack);
		p_list = p_thread;
		p_thread = p_thread->next;

		// free current thread TCB and TCL
		k_task_free_tcb(p_list , 0);	// as above!
	}

	p_thread = p_proc->thread_running;
	if(p_thread->thread == g_p_cur_thread)
	{
		// there must be some errors!
		return;
	}
	else
	{
		// in fact, if run here, it means there must be some errors!
		k_task_free_tcb(p_thread, 0);	// as above!
	}

	// second :free all user virtual space of process
	k_mem_mmu_freeprocessusrspace((unsigned int *)p_proc->fsttb_phy_addr);

	// free some other resources before delete PCB! can add here functions!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

	// last :free PCB
	if(g_p_cur_process == p_proc->parent_proclist)
	{
		// there must be some errors!
		return;
	}
	else
	{
		K_PProcessList temp = p_proc->parent_proclist;
		k_mm_os_heap_free(p_proc);
		k_mm_os_heap_free(temp);
	}
}

/**
 * @BRIEF	: Termiante Thread
 * @PARAM	: threadlist
 * @RETRUN	: void
 * @WARNING	:
 * @NOTE    :
 */
void k_task_terminate_thread(K_PThreadList threadlist)
{
	K_PProcess proc = threadlist->thread->parent_process;
	K_EN_THREAD_STATE	state;

	// check where current thread is belong to current process
	if(threadlist->thread->parent_process != g_p_cur_process)
	{
		// can't terminate a thread in another process!
		return;
	}

	if(threadlist->thread->thread_type == K_TASK_THREAD_TYPE_MAIN)
	{
		// this is main thread, so should terminate the thread's parent process
		k_task_terminate_process((K_PProcessList)((K_PProcess)threadlist->thread->parent_process)->parent_proclist);
		return;
	}

	// disable task schedule
	k_task_disable_schedule();

	state = threadlist->thread->state;
	threadlist->thread->state = K_TASK_THREAD_STATE_TERMINATE;

	// schedule end count
	threadlist->thread->sched_endcnt = threadlist->thread->sched_count;

	switch(state)
	{
		case K_TASK_THREAD_STATE_TERMINATE:
		{
			k_task_enable_schedule();
			return;	// just return...It's has been singled as needing terminate
		}
		case K_TASK_THREAD_STATE_SUSPEND:
		{
			threadlist->thread->sched_count++;	// set flag, that this can't be terminated

			// first remove from thread list
			K_TASK_SCAN_THREAD_REMOVETCB(proc->suspend_threads, threadlist);
			break;
		}
		case K_TASK_THREAD_STATE_ACTIVE:
		{
			threadlist->thread->sched_count++;	// set flag, that this can't be terminated
			K_TASK_SCAN_THREAD_REMOVETCB(proc->active_threads, threadlist);
			break;
		}
		case K_TASK_THREAD_STATE_RUNNING:
		{
			// we shouldn't set flag, because this is running, we must wait it run over!
			// must force task schedule, because current thread can't run continue!
			// k_task_add_thread2list(threadlist, 0, K_TASK_THREAD_STATE_TERMINATE);* schedule will insert list! *

			// free usr mode stack here, just only here can free usr mode stack. Cann't do it in other process cause they have different mm space!
			k_mm_usr_heap_free(threadlist->thread->p_thread_usr_stack);

			// can't enable task schedule! but call forced
			// k_task_enable_schedule();

			// set flag!must do!
			threadlist->thread->state = K_TASK_THREAD_STATE_TERMINATE;

			// process state can't be changed
			k_task_schedule(K_TASK_THREAD_STATE_TERMINATE, ((K_PProcess)threadlist->thread->parent_process)->state, 1);

			// will never run here!
			break;
		}
	}

	// add TCB to terminate list
	k_task_add_thread2list(threadlist, 0, K_TASK_THREAD_STATE_TERMINATE);

	// free usr mode stack here, just only here can free usr mode stack. Cann't do it in other process cause they have different mm space!
	k_mm_usr_heap_free(threadlist->thread->p_thread_usr_stack);

	// enable task schedule!
	k_task_enable_schedule();
}

/**
 * @BRIEF	: Termiante Thread
 * @PARAM	: processlist
 * @RETRUN	: void
 * @WARNING	:
 * @NOTE    :
 */
void k_task_terminate_process(K_PProcessList proclist)
{
	K_EN_PROCESS_STATE state = proclist->process->state;

	// disable task schedule
	k_task_disable_schedule();
	proclist->process->state = K_TASK_PROCESS_STATE_TERMINATE;

	// schedule end count
	proclist->process->sched_endcnt = proclist->process->sched_count;

	switch(state)
	{
		case K_TASK_PROCESS_STATE_TERMINATE:
		{
			k_task_enable_schedule();
			return; // just return;
		}
		case K_TASK_PROCESS_STATE_SUSPEND:
		{
			proclist->process->sched_count++;	// we set flag, that this can't be terminated
			K_TASK_SCAN_PROCESS_REMOVEPCB(g_suspend_process_list, proclist);
			break;
		}
		case K_TASK_PROCESS_STATE_ACTIVE:
		{
			proclist->process->sched_count++;	// we set flag, that this can't be terminated
			K_TASK_SCAN_PROCESS_REMOVEPCB(g_active_process_list, proclist);
			break;
		}
		case K_TASK_PROCESS_STATE_WAITING:
		{
			proclist->process->sched_count++;	// we set flag, that this can't be terminated
			K_TASK_SCAN_PROCESS_REMOVEPCB(g_waiting_process_list, proclist);
			break;
		}
		case K_TASK_PROCESS_STATE_RUNNING:
		{
			// we shouldn't set flag, because this is running, we must wait it run over!
			// Must force *process* schedule, because current process can't run continue!
			// k_task_add_process2list(proclist, K_TASK_PROCESS_STATE_TERMINATE); * schedule will insert list! *

			// can't enable schedule but call forced!
			// k_task_enable_schedule();

			// set flag, tell scheduler do not find thread from this process!
			g_p_cur_process->state = K_TASK_PROCESS_STATE_TERMINATE;

			// thread state can't be terminate, otherwise, will cause double delete error!
			k_task_schedule(K_TASK_THREAD_STATE_ACTIVE, K_TASK_PROCESS_STATE_TERMINATE, 1);
			break;
		}
	}

	// add process to terminate list
	k_task_add_process2list(proclist, K_TASK_PROCESS_STATE_TERMINATE);
	k_task_enable_schedule();
}

/**
 * @BRIEF	: get a process to run in System
 * @PARAM	: void
 * @RETRUN	: void
 * @WARNING	:
 * @NOTE    : Get a PCB from active process list
 */
static K_PProcess k_task_get_next_process(void)
{
	K_PProcessList proc = g_active_process_list.next;

	if(g_p_cur_process->state != K_TASK_PROCESS_STATE_TERMINATE
		&& g_p_cur_process->state != K_TASK_PROCESS_STATE_SUSPEND )
	{
		if(proc == 0)
		{
			// there no process to schedule, so, just use current process
			return g_p_cur_process;
		}

		// check whether need schedule process
		if(proc->process->cur_pri < g_p_cur_process->cur_pri)
		{
			return g_p_cur_process;
		}
	}

	// delete from active process list!
	g_active_process_list.next = proc->next;
	return proc->process;
}

/**
 * @BRIEF	: get a thread to run in System
 * @PARAM	: void
 * @RETRUN	: void
 * @WARNING	:
 * @NOTE    : Get a TCB from thread list in process
 */
static K_PThreadList k_task_get_next_threadelement(void)
{
	K_PProcess p_process = k_task_get_next_process();
	K_PThreadList thread = 0;

	if(g_p_cur_thread->state != K_TASK_THREAD_STATE_TERMINATE
		&& g_p_cur_thread->state != K_TASK_THREAD_STATE_SUSPEND )
	{
		if(p_process == 0)
		{
			// there no other active process, so , still use current ruuning process
			p_process = g_p_cur_process;
		}

		thread = p_process->active_threads.next;

		// check whether need schedule thread
		if(thread == 0)
		{
			// there no other active thread, so, still use current thread
			return g_p_cur_thread->parent_tcblist;
		}

		// check whether need schedule thread
		if(thread->thread->cur_pri < g_p_cur_thread->cur_pri)
		{
			// still use current thread
			return g_p_cur_thread->parent_tcblist;
		}
	}

	// delete from thread list!
	p_process->active_threads.next = thread->next;

	return thread;
}

/**
 * @BRIEF	: task schedule
 * @PARAM	: save_thread_state        after schedule thread insert which list
 * @PARAM	: save_process_state		after schedule process insert which list
 * @PARAM	: isforced					whether igore schedule able state ---1 igore, 0 false!
 * @RETRUN	: void
 * @WARNING	:
 * @NOTE    : schedule task always by thread unit in system.And this must always schedule out current thread!
 */
void k_task_schedule(K_EN_THREAD_STATE save_thread_state, K_EN_PROCESS_STATE save_process_state, int isforced)
{
	K_PThread pthread;
	K_PThreadList pthreadlist;

	// Disable interrupt!
	K_MEM_DISABLE_INTERRUPT;

	// check whether there're process or thread need to be terminated!
	k_task_thread_terminate_thread();
	k_task_process_terminate_process();

	if(isforced)
	{
		k_task_enable_schedule();
	}

	// check whether enable task schedule
	if(!k_task_is_schedule_enable())
	{
		// can't schedule task now!
		return;
	}

	// we need to find a thread to switch
	pthreadlist = k_task_get_next_threadelement();
	if(g_p_cur_thread == pthread && pthread->state != K_TASK_THREAD_STATE_TERMINATE)
	{
		// don't need to schedule!
		return;
	}

	if(pthread->state == K_TASK_THREAD_STATE_TERMINATE)
	{
		// there must be some error! gotten thread can't be terminate thread!
		return;
	}

	pthread = pthreadlist->thread;

	// set scheduled count!
	g_p_cur_process->sched_count++;
	g_p_cur_thread->sched_count++;

	// set next priority
	g_p_cur_process->priority = k_task_next_priority(g_p_cur_process->cur_pri, g_p_cur_process->priority);
	g_p_cur_thread->priority = k_task_next_priority(g_p_cur_thread->cur_pri, g_p_cur_thread->priority);

	// whether need to save thread
	if(g_p_cur_thread != pthread)
	{
		g_p_cur_thread->state = save_thread_state;
		// !!!!!!!!!!!! we need insert in to correspoud list     thread or process !!!!!!!!
		k_task_add_thread2list(g_p_cur_thread->parent_tcblist, g_p_cur_thread->parent_process, save_thread_state);
	}

	// whether need to save process
	if(pthread->parent_process != g_p_cur_process)
	{
		g_p_cur_process->state = save_process_state;
		k_task_add_process2list(g_p_cur_process->parent_proclist, save_process_state);
	}

	// save current thread context, including cpu context and other context
	K_TASK_CPU_CONTEXT_SAVE(g_p_cur_thread);

	// save cp15 context and other processor context!

/*	... */
	//


/*---------------------------------------------------------------------------------------*/
	// resume a thread...check whether it's a new thread.

	// first check whether need to swich MMU.(if process has not been changed, just do nothing,
	// because, MMU change will need much time!)
	if(pthread->parent_process != g_p_cur_process)
	{
		k_mmu_switch(((K_PProcess)pthread->parent_process)->fsttb_phy_addr);
	}

	if(pthread->state == K_TASK_THREAD_STATE_NEW)
	{
		// change flag to normal state
		pthread->state = K_TASK_THREAD_STATE_RUNNING;
		((K_PProcess)pthread->parent_process)->state = K_TASK_PROCESS_STATE_RUNNING;
		g_p_cur_thread = pthread;
		g_p_cur_process = pthread->parent_process;
		// resume the cp15 and other processor context
/* .............*/
		//

		// this is a new thread.so we should directly running it.
		K_TASK_NEW_CONTEXT_RESUME(pthread, e_thread_start_addr);

		// should not enable interrupt, because e_thread_start_addr will do this!
	}
	else
	{
		// resume the cp15 and other processor context!
/*		... */
		//

		K_TASK_CPU_CONTEXT_RESUME(pthread);
		pthread->state = K_TASK_THREAD_STATE_RUNNING;
		((K_PProcess)pthread->parent_process)->state = K_TASK_PROCESS_STATE_RUNNING;
		g_p_cur_thread = pthread;
		g_p_cur_process = pthread->parent_process;
		K_MEM_ENABLE_INTERRUPT;
	}
}

/**
 * @BRIEF	: Check whether task schedule enabled
 * @PARAM	: void
 * @RETRUN	: !0 enable, 0 disabled
 * @NOTE	: This function just checks the flag!Dose nothing else!
 */
unsigned int k_task_is_schedule_enable(void)
{
	if(g_task_schedule_state)
	{
		return 0;
	}
	return 1;
}

/**
 * @BRIEF	: Disable task schedule
 * @PARAM	: void
 * @RETRUN	: void
 * @NOTE	: This function just set a flag.Does nothing else.
 */
void k_task_disable_schedule(void)
{
	g_task_schedule_state = 1;
}

/**
 * @BRIEF	: Enable task schedule
 * @PARAM	: void
 * @RETRUN	: void
 * @NOTE	: This function just set a flag.Does nothing else.
 */
void k_task_enable_schedule(void)
{
	g_task_schedule_state = 0;
}

/**
 * @BRIEF	: Add thread to specified thread list
 * @PARAM	: thread  TCB
 * @PARAM	: process TCB of PCB
 * @PARAM	: state	  State of thread list to be added
 * @RETRUN	: void
 * @NOTE	: This function doesn't disable task schedule!
 */
void k_task_add_thread2list(K_PThreadList thread, K_PProcess process, K_EN_THREAD_STATE state)
{
	if(state == K_TASK_THREAD_STATE_SUSPEND)
	{
		thread->next = process->suspend_threads.next;
		process->suspend_threads.next = thread;
		return;
	}
	if(state == K_TASK_THREAD_STATE_ACTIVE)
	{
		// insert thread in order by current priority!
		K_PThreadList tl_cur = process->active_threads.next;
		K_PThreadList tl_pre = &process->active_threads;
		while(tl_cur)
		{
			if(thread->thread->cur_pri > tl_cur->thread->cur_pri)
			{
				thread->next = tl_cur;
				tl_pre->next = thread;
				return;
			}
			tl_pre = tl_cur;
			tl_cur = tl_cur->next;
		}

		// insert to last
		thread->next = 0;
		tl_pre->next = thread;
		return;
	}
	if(state == K_TASK_THREAD_STATE_TERMINATE)
	{
		thread->next = g_terminate_threadlist.next;
		g_terminate_threadlist.next = thread;
		return;
	}

	// can't add other state threads.
	return;
}

/**
 * @BRIEF	: Add Process to specified process list
 * @PARAM	: process  TCB
 * @PARAM	: state	  State of process list to be added
 * @RETRUN	: void
 * @NOTE	: This function doesn't disable task schedule!
 */
void k_task_add_process2list(K_PProcessList process, K_EN_PROCESS_STATE state)
{
	if(state == K_TASK_PROCESS_STATE_SUSPEND)
	{
		process->next = g_suspend_process_list.next;
		g_suspend_process_list.next = process;
		return;
	}
	if(state == K_TASK_PROCESS_STATE_ACTIVE)
	{
		// insert process in order!
		K_PProcessList pl_cur = g_active_process_list.next;
		K_PProcessList pl_pre = &g_active_process_list;
		while(pl_cur)
		{
			if(process->process->cur_pri > pl_cur->process->cur_pri)
			{
				process->next = pl_cur;
				pl_pre->next = process;
				return;
			}
			pl_pre = pl_cur;
			pl_cur = pl_cur->next;
		}

		// insert to last
		process->next = 0;
		pl_pre->next = process;
		return;
	}
	if(state == K_TASK_PROCESS_STATE_WAITING)
	{
		process->next = g_waiting_process_list.next;
		g_waiting_process_list.next = process;
		return;
	}
	if(state == K_TASK_PROCESS_STATE_TERMINATE)
	{
		process->next = g_terminate_processlist.next;
		g_terminate_processlist.next = process;
		return;
	}
	// can't add other state
	return;
}

/**
 * @BRIEF	: thread terminate process
 * @PARAM	: void
 * @RETRUN	: void
 * @NOTE	: This function doesn't disable task schedule!
 * 			: This function do the real thread terminating!
 * 			: This function called only by kernel and any others can't call this!
 */
static void k_task_thread_terminate_thread(void)
{
	// scan thread terminate list, find out which can be terminated(as, the schedule count must not be equ with end count)
	K_PThreadList cur_tl = g_terminate_threadlist.next;
	K_PThreadList pre_tl = &g_terminate_threadlist;

	while(cur_tl)
	{
		if(cur_tl->thread->sched_count != cur_tl->thread->sched_endcnt)
		{
			// this thread can be terminated!
			pre_tl->next = cur_tl->next;
			// terminate it!In fact, here just free thread kernel stack and TCB. user stack has been freed before added into list!
			k_task_free_tcb(cur_tl, 0);
			cur_tl = pre_tl->next;
		}
		else
		{
			pre_tl = cur_tl;
			cur_tl = cur_tl->next;
		}
	}
}

/**
 * @BRIEF	: process terminate process
 * @PARAM	: void
 * @RETRUN	: void
 * @NOTE	: This function doesn't disable task schedule!
 * 			: This function do the real thread terminating!
 * 			: This function called only by kernel and any others can't call this!
 */
static void k_task_process_terminate_process(void)
{
	// scan process terminate list, find out which can be terminated(as, the schedule count must not be equ with end count)
	K_PProcessList pl_cur = g_terminate_processlist.next;
	K_PProcessList pl_pre = &g_terminate_processlist;

	while(pl_cur)
	{
		if(pl_cur->process->sched_count != pl_cur->process->sched_endcnt)
		{
			// this process can be terminated
			pl_pre->next = pl_cur->next;
			k_task_free_pcb(pl_cur->process);
			pl_cur = pl_pre->next;
		}
		else
		{
			pl_pre = pl_cur;
			pl_cur = pl_cur->next;
		}
	}
}

/**
 * @BRIEF	: compute next cpu times priority of task
 * @PARAM	: cur_pri	current priority of task
 * @RETRUN	: next priority of task
 * @NOTE	: This function doesn't disable task schedule!
 * 			: This function called only by kernel and any others can't call this!
 */
static K_EN_TASK_PRIORITY k_task_next_priority(K_EN_TASK_PRIORITY cur_pri, K_EN_TASK_PRIORITY max_pri)
{
	switch(cur_pri)
	{
		case K_TASK_THREAD_PRIORITY_LOWEST: return max_pri;
		case K_TASK_THREAD_PRIORITY_LOW: return K_TASK_THREAD_PRIORITY_LOWEST;
		case K_TASK_THREAD_PRIORITY_NORMAL: return K_TASK_THREAD_PRIORITY_LOW;
		case K_TASK_THREAD_PRIORITY_HIGHT: return K_TASK_THREAD_PRIORITY_NORMAL;
		case K_TASK_THREAD_PRIORITY_HIGHTEST: return K_TASK_THREAD_PRIORITY_HIGHT;
		default: return K_TASK_THREAD_PRIORITY_HIGHT;
	}
	return K_TASK_THREAD_PRIORITY_HIGHT;
}

/**
 * @BRIEF	: Suspend Thread
 * @PARAM	: threadlist	TCBL witch will be suspended
 * @RETRUN	: void
 * @NOTE	: This function doesn't disable task schedule!
 * 			: This function called only by kernel and any others can't call this!
 */
void k_task_suspend_thread(K_PThreadList threadlist)
{
	switch(threadlist->thread->state)
	{
		case K_TASK_THREAD_STATE_NEW:
		case K_TASK_THREAD_STATE_ACTIVE:
		{
			k_task_disable_schedule();
			// remove from activing list
			threadlist->thread->state = K_TASK_THREAD_STATE_SUSPEND;
			K_TASK_SCAN_THREAD_REMOVETCB(((K_PProcess)threadlist->thread->parent_process)->active_threads, threadlist);
			k_task_add_thread2list(threadlist->thread->parent_tcblist, threadlist->thread->parent_process,
				K_TASK_THREAD_STATE_SUSPEND);
			k_task_enable_schedule();
			break;
		}

		case K_TASK_THREAD_STATE_RUNNING:
		{
			// current is running, set flag, and force schedule!
			threadlist->thread->state = K_TASK_THREAD_STATE_SUSPEND;
			k_task_schedule(K_TASK_THREAD_STATE_SUSPEND, ((K_PProcess)threadlist->thread->parent_process)->state, 0);
			break;
		}

		default:
			// just return.
			return;
	}
}

/**
 * @BRIEF	: Resume Thread
 * @PARAM	: threadlist	TCBL witch will be Resume
 * @RETRUN	: void
 * @NOTE	: This function doesn't disable task schedule!
 * 			: This function called only by kernel and any others can't call this!
 */
void k_task_resume_thread(K_PThreadList threadlist)
{
	if(threadlist->thread->state != K_TASK_THREAD_STATE_SUSPEND)
		return;

	k_task_disable_schedule();
	// remove from suspend list
	K_TASK_SCAN_THREAD_REMOVETCB(((K_PProcess)threadlist->thread->parent_process)->suspend_threads, threadlist);
	// add it to active list
	k_task_add_thread2list(threadlist, threadlist->thread->parent_process, K_TASK_THREAD_STATE_ACTIVE);
	k_task_enable_schedule();
}

/**
 * @BRIEF	: Suspend Process
 * @PARAM	: processlist	PCBL witch will be suspend
 * @RETRUN	: void
 * @NOTE	: This function doesn't disable task schedule!
 * 			: This function called only by kernel and any others can't call this!
 */
void k_task_suspend_process(K_PProcessList proclist)
{
	switch(proclist->process->state)
	{
		case K_TASK_PROCESS_STATE_ACTIVE:
		{
			k_task_disable_schedule();
			// remove from activing list
			proclist->process->state = K_TASK_PROCESS_STATE_SUSPEND;
			K_TASK_SCAN_PROCESS_REMOVEPCB(g_active_process_list, proclist);
			k_task_add_process2list(proclist, K_TASK_PROCESS_STATE_SUSPEND);
			k_task_enable_schedule();
			break;
		}

		case K_TASK_PROCESS_STATE_RUNNING:
		{
			// current is running, set flag, and force schedule!
			proclist->process->state = K_TASK_PROCESS_STATE_SUSPEND;
			k_task_schedule(K_TASK_THREAD_STATE_ACTIVE, K_TASK_PROCESS_STATE_SUSPEND, 0);
			break;
		}

		default:
			// just return.
			return;
	}
}

/**
 * @BRIEF	: Resume Process
 * @PARAM	: processlist	PCBL witch will be suspend
 * @RETRUN	: void
 * @NOTE	: This function doesn't disable task schedule!
 * 			: This function called only by kernel and any others can't call this!
 */
void k_task_resume_process(K_PProcessList proclist)
{
	if(proclist->process->state != K_TASK_PROCESS_STATE_SUSPEND)
		return;

	k_task_disable_schedule();
	// remove from suspend list
	K_TASK_SCAN_PROCESS_REMOVEPCB(g_suspend_process_list, proclist);
	// add to active list
	k_task_add_process2list(proclist, K_TASK_PROCESS_STATE_ACTIVE);
	k_task_enable_schedule();
}

#endif /* _K_TASK_C_ */

